#ifndef _GKV_HPP
#define _GKV_HPP
#include "gkv_global.hpp"

namespace gkv
{

typedef unsigned long dword_t; // 4 bytes
typedef unsigned char byte_t; // 1 byte

// File List Structure for convenience
// 16 bytes, this one doesn't matter (not being written to a file)
typedef struct filelist_t
{
    std::string                 path;
    std::vector<std::string>    theList;
} filelist_t;

// GKV File Header
// 16 bytes (8+4+1=13, where are my other 3 bytes?)
// 8+4+4 = 16 bytes used
typedef struct header_t
{
	// char = 1 byte
	// char* = 4 bytes
	// 8 bytes
	char gkvSignature[8];						// (GKV)+(MAJOR)+(MINOR)+
												// (D)eveloper -or- (P)ublic+
												// (Z)lib (C)ompression -or- (N)o (C)ompression
												// Defaults to (G)(K)(V)(E)mpty(S)ignature(\0)
												// The other possible value is DUMMIE
												// Example:
												//	* "GKV00ES\0" = Initial value
												//	* "GKV01DZC" = 0.0.999.release
												//	* "GKV01PNC" = 0.1.0.release
												//	* "GKVDUMMY" = An error occurred
	// 4 bytes
	dword_t numFTEntries;						// Number of file table entries
	// 1 byte (4 bytes used in gkv file)
	bool isCompressed;							// Compressed = true, Not compressed = false
} header_t;

// Table Entry per file in the GKV file
// 268 bytes (264 + 4 void*)
typedef struct tableentry_t
{
	char					guid[256];				// Name of one path+filename in the GKV file
													// Windows MAX_PATH = 260 (- 4 for the drive letter)

	dword_t					fileSize;				// The size of the file in bytes
	dword_t					compSize;				// The size of the compressed file in bytes
	dword_t					offset;					// Offset of file in the GKV
	tableentry_t*	    	nextFTEntry;			// Next file table entry (is a linked list)

	// Constructor
	tableentry_t()
	{
		memset(guid, 0, sizeof(guid));
		fileSize = 0;
		offset = 0;
		nextFTEntry = 0;
	}

	// Deconstructor
	~tableentry_t()
	{
		memset(guid, 0, sizeof(guid));
		fileSize = 0;
		offset = 0;
		delete nextFTEntry;
	}

} tableentry_t;


/////////////////////////////////////////////////////////////////////////////////////////////

class GKV_File
{
	private:
		header_t			    m_Header;					    // The header of the GKV file
		tableentry_t*		    m_FileTable;				    // The master file table for the GKV

		// Private Members
		// Generates a list of files to be packaged
		// Returns a string containing the generated output filename
		std::string generateFileList(
                    std::string dir_path, 		                // <- directory to scan
                    std::list<filelist_t> &rootList,            // <- The list of files to generate
					int trim, bool is_root=true);	            // <- #chars to trim off the root,
																//    is this the root dir?
		bool generateHFT(std::list<filelist_t> &rootList, 		// Create a Header and File Table
						std::string working_path,
						dword_t &fileCount,
						bool compressed = false);		    	// defaults to NOT COMPRESSED
		bool workOutOffsets(void);								// Work out the file offsets in the GKV
		char* getEscapedValue(char* to_escape, int size);
		bool fetchHeader(std::string gkvfile);					// Fetch the header information
		bool fetchFileTable(std::string gkvfile);				// Fetch the file table information
																// FetchHeader must be called before this!


	public:
		GKV_File();												// Constructor
		~GKV_File();									        // Deconstructor


		// Public Members
		std::string create(std::string dirpath);				// Creates a new GKV archive
																// returns name of file created
		std::string createZ(std::string dirpath);				// create() with compression enabled

		bool list(std::string gkvfile);							// Lists the contents of a GKV archive
		bool extractAll(std::string gkvfile);					// Extracts a GKV archive into current directory

		// Retrieve a handle to a single file in package.
		// To be used to extract the data of a single file in your program.
		byte_t* getFileData(std::string gkvfile, std::string guid, int* size);

		/* Not implemented.
		// Pass the gkvfile, the path_to_file in the archive, and mode
		SDL_RWops* SDL_RWFromGKV(const char* gkvfile,
								 const char* path_to_file,
								 const char* mode);
		*/
};

} // namespace

#endif
